﻿using System;
using System.Collections.Generic;
using System.Linq;
using MiniCrawler.DataAccess;
using MiniCrawler.DataAccess.Repositories;
using MiniCrawler.Entity;
using MiniCrawler.Logging;
using MiniCrawler.UrlFilter;

namespace MiniCrawler.Business.Collectors.LinkCollectors
{
    public class LinkCollector : ILinkCollector
    {
        public Thread thread;
        public List<CategoryExpressionObject> categoryExpressions;
        public List<DataExpressionObject> dataExpressions;
        public DateTime start;

        public LinkCollector()
        {
            var configHelper = new ConfigHelper();
            this.thread = configHelper.GetFirstThread();
            InitializeExpressionLists();
        }
        public LinkCollector(int threadId)
        {
            var configHelper = new ConfigHelper();
            this.thread = configHelper.GetThreadById(threadId);
            InitializeExpressionLists();
        }

        public void InitializeExpressionLists()
        {
            var configHelper = new ConfigHelper();
            var categoryExpsObjects = configHelper.GetCategoryExpressionesByThreadId(thread.Id);
            if (categoryExpsObjects != null)
            {
                categoryExpressions = new List<CategoryExpressionObject>();
                foreach (var categoryExpression in categoryExpsObjects.ToList())
                {
                    var obj = new CategoryExpressionObject(categoryExpression);
                    categoryExpressions.Add(obj);
                }
            }

            var dataExpsObjects = configHelper.GetDataExpressionesByThreadId(thread.Id);
            if (dataExpsObjects != null)
            {
                dataExpressions = new List<DataExpressionObject>();
                foreach (var dataExpression in dataExpsObjects.ToList())
                {
                    var obj = new DataExpressionObject(dataExpression);
                    dataExpressions.Add(obj);
                }
            }
        }

        public void Run()
        {
            //return;
            start = DateTime.Now;

            string html = Common.GetWebPage(thread.HostName);

            var s = 0;
            var t0 = Utils.GetAllLinks(html);

            // Get from homepage

            GetAllCategoryLinks(t0);

            Log.WriteElapseTime(start);

            GetAllNewsLink(t0);

            Log.WriteElapseTime(start);

            // Scan cat link
            while (CategoryLinkHelper.HasUncheckedLinks(thread.HostName, 1))
            {

                var catLink = CategoryLinkHelper.SelectUncheckedLinks(thread.HostName, 1)[0];

                Log.WriteLog("[CATEGORY : " + CategoryLinkHelper.SelectLinks(thread.HostName, 1).Count + "][UNCHECKED : " + CategoryLinkHelper.SelectUncheckedLinks(thread.HostName, 1).Count + "]");
                Log.WriteLog("[NEWS     : " + DataLinkHelper.SelectLinks(thread.HostName, 2).Count + "][UNCHECKED : " + DataLinkHelper.SelectUncheckedLinks(thread.HostName, 2).Count + "]");

                string cathtml = Common.GetWebPage(FillAbsoluteUrl(thread.HostName, catLink.Value));

                GetAllCategoryLinks(Utils.GetAllLinks(cathtml));
                GetAllNewsLink(Utils.GetAllLinks(cathtml));

                catLink.IsChecked = true;
                CategoryLinkHelper.UpdateLink(catLink);

                Log.WriteElapseTime(start);
            }

            Log.WriteLog("STOP RUNNING");
        }

        public void RunGetBook()
        {
            //return;
            start = DateTime.Now;

            string html = Common.GetWebPage(thread.HostName);

            var s = 0;
            var t0 = Utils.GetAllLinks(html);

            // Get from homepage

            GetAllCategoryLinks(t0);

            Log.WriteElapseTime(start);

            GetAllNewsLink(t0);

            Log.WriteElapseTime(start);

            // Scan cat link
            while (CategoryLinkHelper.HasUncheckedLinks(thread.HostName, 1))
            {

                var catLink = CategoryLinkHelper.SelectUncheckedLinks(thread.HostName, 1)[0];
                catLink.Value = catLink.Value;

                Log.WriteLog("[CATEGORY : " + CategoryLinkHelper.SelectLinks(thread.HostName, 1).Count + "][UNCHECKED : " + CategoryLinkHelper.SelectUncheckedLinks(thread.HostName, 1).Count + "]");
                Log.WriteLog("[NEWS     : " + DataLinkHelper.SelectLinks(thread.HostName, 2).Count + "][UNCHECKED : " + DataLinkHelper.SelectUncheckedLinks(thread.HostName, 2).Count + "]");

                string cathtml = Common.GetWebPage(FillAbsoluteUrl(thread.HostName, catLink.Value + "&textbook=1"));

                GetAllCategoryLinks(Utils.GetAllLinks(cathtml));
                GetAllBookNewsLink(Utils.GetAllLinks(cathtml));

                catLink.IsChecked = true;
                CategoryLinkHelper.UpdateLink(catLink);

                Log.WriteElapseTime(start);
            }

            Log.WriteLog("STOP RUNNING");
        }

        public bool IsCategoryLink(string url)
        {
            var t = GetSatisfyCategoryExpression(categoryExpressions, url);
            if (t != null) return true;
            else return false;
        }

        public bool IsDataLink(string url)
        {
            //if (IsCategoryLink(url)) return false;
            var t = GetSatisfyDataExpression(dataExpressions, url);
            if (t != null) return true;
            else return false;
        }

        public int GetAllCategoryLinks(List<string> allLinks)
        {
            try
            {
                if (allLinks.Count > 0)
                {
                    foreach (var link1 in allLinks)
                    {
                        var link = FillAbsoluteUrl(thread.HostName, link1);
                        if (IsCategoryLink(link) && !CategoryLinkHelper.IsLinkExist(link))
                        {
                            var t = GetSatisfyCategoryExpression(categoryExpressions, link);
                            if(t!=null && t.CategoryExpression.IsEnabled)
                            {
                                var newLink = new CategoryLink
                                {
                                    DateCreated = DateTime.Now,
                                    IsChecked = false,
                                    Level = 1,
                                    Value = link,
                                    Website = thread.HostName,
                                    CategoryExpressionId = t.CategoryExpression.Id
                                };

                                // CategoryLinkHelper.CreateLink(newLink);
                            }

                            
                        }
                    }
                }
                return 1;
            }
            catch (Exception ex)
            {
                LogService.Service.Error(ex);
                return -1;
            }

        }

        public int GetAllNewsLink(List<string> allLinks)
        {
            try
            {
                if (allLinks.Count > 0)
                {
                    foreach (var link1 in allLinks)
                    {
                        var link = FillAbsoluteUrl(thread.HostName, link1);
                        if (IsDataLink(link) && !DataLinkHelper.IsLinkExist(link))
                        {
                            var t = GetSatisfyDataExpression(dataExpressions, link);
                            if (t != null && t.DataExpression.IsEnabled)
                            {
                                var newLink = new DataLink
                                                  {
                                                      DateCreated = DateTime.Now,
                                                      IsChecked = false,
                                                      Level = 2,
                                                      Value = link,
                                                      Website = thread.HostName,
                                                      DataExpressionId = t.DataExpression.Id
                                                  };

                                DataLinkHelper.CreateLink(newLink);
                            }
                        }
                    }
                }
                return 1;
            }
            catch (Exception ex)
            {
                LogService.Service.Error(ex);
                return -1;
            }

        }

        public int GetAllBookNewsLink(List<string> allLinks)
        {
            try
            {
                if (allLinks.Count > 0)
                {
                    foreach (var link1 in allLinks)
                    {
                        var link = FillAbsoluteUrl(thread.HostName, link1);
                        // Process this
                        var index = link.LastIndexOf("?");
                        if (index != -1) link = link.Substring(0, index);

                        if (IsDataLink(link) && !DataLinkHelper.IsLinkExist(link))
                        {
                            var t = GetSatisfyDataExpression(dataExpressions, link);

                            if (t != null && t.DataExpression.IsEnabled)
                            {
                                var newLink = new DataLink
                                {
                                    DateCreated = DateTime.Now,
                                    IsChecked = false,
                                    Level = 2,
                                    Value = link,
                                    Website = thread.HostName,
                                    DataExpressionId = t.DataExpression.Id
                                };

                                DataLinkHelper.CreateLink(newLink);
                            }
                        }
                    }
                }
                return 1;
            }
            catch (Exception ex)
            {
                LogService.Service.Error(ex);
                return -1;
            }

        }

        public CategoryExpressionObject GetSatisfyCategoryExpression(List<CategoryExpressionObject> expression, string link)
        {
            if (link.Trim().EndsWith("/")) link = link.Trim().Substring(0, link.Length - 1);

            foreach (var exp in expression)
            {
                if (exp.ExpressionObject.IsMatch(link)) 
                    return exp;
            }
            return null;
        }

        public DataExpressionObject GetSatisfyDataExpression(List<DataExpressionObject> expression, string link)
        {
            if (link.Trim().EndsWith("/")) link = link.Trim().Substring(0, link.Length - 1);

            foreach (var exp in expression)
            {
                if (exp.ExpressionObject.IsMatch(link))
                    return exp;
            }
            return null;
        }

        public string FillAbsoluteUrl(string hostName, string url)
        {
            if (url.StartsWith("/")) return (hostName + url).Replace("//", "/").Replace("http:/","http://");

            else return url;
        }
    }
}
